/*
 * @(#)Terminal.java	1.0 Apr 18, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.io.console;

import java.io.*;
import java.util.regex.*;
import java.util.*;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;

public class Terminal
{
	public enum DefinedEnv
	{
		prompt, user, curdir, homedir, consoleWidth,
		DEFAULT_PROMPT, DEFAULT_CURDIR, DEFAULT_HOMEDIR, DEFAULT_USERNAME,
		DEFAULT_CONSOLE_WIDTH
	}
	protected Console console;
	protected Environment env;
	protected PropertyChangeSupport changes;

	private static final String NEWLINE_FMT = "\n";
	private static final String ERR_FMT = "%s\n\n";

	public Terminal()
			throws IOException
	{
		console = System.console();
		if(console == null)
			throw new IOException("Console not supported on this platform.");

		changes = new PropertyChangeSupport(this);
	}

	public void addPropertyChangeListener(PropertyChangeListener listener)
	{
		changes.addPropertyChangeListener(listener);
	}
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
	{
		changes.addPropertyChangeListener(propertyName, listener);
	}
	public void addPropertyChangeListener(DefinedEnv defined, PropertyChangeListener listener)
	{
		addPropertyChangeListener(defined.toString(), listener);
	}
	public void removePropertyChangeListener(PropertyChangeListener listener)
	{
		changes.removePropertyChangeListener(listener);
	}
	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
	{
		changes.removePropertyChangeListener(propertyName, listener);
	}
	public void removePropertyChangeListener(DefinedEnv defined, PropertyChangeListener listener)
	{
		removePropertyChangeListener(defined.toString(), listener);
	}


	public void setDefaults()
	{
		setEnv(DefinedEnv.DEFAULT_PROMPT, "> ");
		setEnv(DefinedEnv.DEFAULT_CURDIR, new File("."));
		setEnv(DefinedEnv.DEFAULT_HOMEDIR, new File(System.getProperty("user.home", ".")));
		setEnv(DefinedEnv.DEFAULT_USERNAME, "guest");
		setEnv(DefinedEnv.DEFAULT_CONSOLE_WIDTH, "132");
	}

	public void resetEnvironment()
	{
		env = new Environment();
		setDefaults();

		if(getPrompt() == null)
			setPrompt(getEnv(DefinedEnv.DEFAULT_PROMPT));

		setCurrentPath(getEnv(DefinedEnv.DEFAULT_CURDIR));
		setHomePath(getEnv(DefinedEnv.DEFAULT_HOMEDIR));

		if(getUser() == null)
			setUser(getEnv(DefinedEnv.DEFAULT_USERNAME));

		if(getConsoleWidth() == -1)
			setConsoleWidth(Integer.parseInt(getEnv(DefinedEnv.DEFAULT_CONSOLE_WIDTH)));
	}

	public Environment getEnvironment(){return env;}
	public void setEnv(String key, String value)
	{
		String eld = env.get(key);
		env.put(key, value);
		changes.firePropertyChange(key, eld, value);
	}
	public void setEnv(String key, File value)
	{
		String eld = env.get(key);
		env.put(key, value);
		changes.firePropertyChange(key, eld, env.get(key));
	}
	public String getEnv(String key){return env.get(key);}
	public void setEnv(DefinedEnv defined, File value){setEnv(defined.toString(), value);}
	public void setEnv(DefinedEnv defined, String value){setEnv(defined.toString(), value);}
	public String getEnv(DefinedEnv defined){return getEnv(defined.toString());}
	public String getPrompt(){return getEnv(DefinedEnv.prompt);}
	public void setPrompt(String prompt){setEnv(DefinedEnv.prompt, prompt);}
	public String getUser(){return getEnv(DefinedEnv.user);}
	public void setUser(String user){setEnv(DefinedEnv.user, user);}
	public String getCurrentPath(){return getEnv(DefinedEnv.curdir);}
	public void setCurrentPath(String path){setEnv(DefinedEnv.curdir, path);}
	public File getCurrentDirectory(){return new File(getCurrentPath());}
	public void setCurrentDirectory(File dir){setEnv(DefinedEnv.curdir, dir);}
	public String getHomePath(){return getEnv(DefinedEnv.homedir);}
	public void setHomePath(String path){setEnv(DefinedEnv.homedir, path);}
	public File getHomeDirectory(){return new File(getHomePath());}
	public void setHomeDirectory(File dir){setEnv(DefinedEnv.homedir, dir);}
	public int getConsoleWidth()
	{
		String width = getEnv(DefinedEnv.consoleWidth);
		if(width == null) return -1;
		try{
			return Integer.parseInt(width);
		}catch(Exception e){
			error(e);
			return -1;
		}
	}
	public void setConsoleWidth(int width){setEnv(DefinedEnv.consoleWidth, String.format("%d", width));}

	public PrintWriter writer(){return console.writer();}
	public Reader reader(){return console.reader();}
	public Console format(String fmt, Object... args){return console.format(fmt, args);}
    public Console printf(String format, Object... args){return console.printf(format, args);}
	public String readLine(String fmt, Object... args){return console.readLine(fmt, args);}
	public String readLine(){return console.readLine();}
	public char[] readPassword(String fmt, Object... args){return console.readPassword(fmt, args);}
	public char[] readPassword(){return console.readPassword();}
	public void flush(){console.flush();}
	public void println(){format(NEWLINE_FMT);}
	public void println(String msg){format("%s\n", msg);}

	public List<String> readArgs()
	{
		return new ArrayList<String>(Arrays.asList(readLine().split(" ")));
	}

	public List<String> readArgs(String fmt, Object ... args)
	{
		return new ArrayList<String>(Arrays.asList(readLine(fmt, args).split(" ")));
	}

	public List<String> promptArgs()
	{
		return readArgs(getPrompt());
	}

	public void error(Throwable cause)
	{
		error(cause, true);
	}

	public void error(Throwable cause, boolean printStackTrace)
	{
		format(ERR_FMT, cause.getMessage());
		if(printStackTrace) cause.printStackTrace(writer());
	}
}
